package com.xinyuan.digit.next.subscriber.db.util;

import com.xinyuan.digit.next.api.subscriber.annotations.db_ignore;
import com.xinyuan.digit.next.common.enums.BaseEnum;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by doodt on 2020/6/4.
 */
public class LocalObjectUtil {

    public static Set<String> getNotNullPropertyNameSet(Class clazz, Object source) {
        return getPropertyNameSet(false, clazz, source);
    }

    public static Set<String> getPropertyNameSet(boolean isNull, Class clazz, Object source) {
        return getPropertyNameSet(isNull, clazz, source, true);
    }

    private static Set<String> getPropertyNameSet(boolean isNull, Class clazz, Object source, boolean needSuper) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<>();
        Map<String, Field> fieldMap = new HashMap<>();
        List<Field> fieldList = new ArrayList<>();
        fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
        if (needSuper && clazz.getSuperclass() != Object.class) {
            fieldList.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        }
        fieldMap = fieldList.stream().collect(Collectors.toMap(Field::getName, t -> t, (k1, k2) -> k1));
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            //拦截非枚举类
            if ("class".equalsIgnoreCase(pd.getName()) && !pd.getClass().isAssignableFrom(BaseEnum.class)) continue;
            //拦截标识了数据库忽略字段
            if (fieldMap.get(pd.getName()) == null || fieldMap.get(pd.getName()).isAnnotationPresent(db_ignore.class))
                continue;
            if (isNull) {
                if (ObjectUtils.isEmpty(srcValue)) emptyNames.add(pd.getName());
            } else {
                if (srcValue != null) emptyNames.add(pd.getName());
            }
        }
        return emptyNames;
    }

    public static List<String> getPropertyNameList(Class clazz, List<String> nameList) {
        return getPropertyNameList(clazz, nameList, true);
    }

    private static List<String> getPropertyNameList(Class clazz, List<String> nameList, boolean needSuper) {
        Field[] pFields = clazz.getFields();
        List<Field> fieldList = Arrays.asList(pFields);
        Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
            if (fieldList.contains(field)) return;
            if (field.isAnnotationPresent(db_ignore.class)) return;
            nameList.add(LambdaUtils.toLowerCaseFirstOne(field.getName()));
        });
        if (needSuper && clazz.getSuperclass() != Object.class) {
            getPropertyNameList(clazz.getSuperclass(), nameList);
        }
        return nameList;
    }

    public static String[] getPropertyNameLines(Class clazz) {
        List<String> nameList = getPropertyNameList(clazz, new ArrayList<>());
        String[] names = new String[nameList.size()];
        for (int i = 0; i < nameList.size(); i++) {
            names[i] = LambdaUtils.camelToUnderline(nameList.get(i));
        }
        return names;
    }
}
